/**
 * 跨操作系统统一接口实现 for FreeRTOS (Xilinx 移植版本 10.0)
 */

#include <stdio.h>
#include <time.h>

#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <semphr.h>
#include <event_groups.h>

#include "mcu.h"
#include "unios.h"
#include "utils.h"

#include "log.h"
#define LOGLEVEL LOG_DEBUG
#define LOGTAG   "unios"
#include "log4app.h"


// ======================================================================================
// 基础功能
// ======================================================================================

void* unios_malloc(size_t size) {
	// 使用 FreeRTOS 的内存管理机制分配内存
	return pvPortMalloc(size);
}

void unios_free(void *ptr) {
	// 使用 FreeRTOS 的内存管理机制释放内存
	if(ptr) vPortFree(ptr);
}

void* unios_malloc0(size_t size) {
	void* mem = unios_malloc(size);
	return mem ? memset(mem, 0, size) : NULL;
}

size_t unios_get_cpu_core_count() {
	return 1;
}

void* unios_get_pointer(const void *stream) {
	return mcu_get_pointer(stream);
}

unios_us_t unios_us_now() {
    return mcu_clock_us_now();
}

unios_ms_t unios_ms_now() {
    return mcu_clock_ms_now();
}

void unios_us_delay(unios_us_t us) {
	mcu_clock_us_delay(us);
}

void unios_ms_delay(unios_ms_t ms) {
	mcu_clock_ms_delay(ms);
}

unios_ms_t unios_ms_elapsed(unios_ms_t earlier_time_ms) {
	unios_ms_t now = unios_ms_now();
    if(now < earlier_time_ms) return UINT64_MAX - earlier_time_ms + now;
    return now - earlier_time_ms;
}

void unios_watchdog_feed() {
	mcu_watchdog_feed();
}

unios_sec_t unios_rtcsec_get() {
	return mcu_clock_get_rtcsec();
}

std_err_t unios_rtcsec_set(unios_sec_t sec) {
	return mcu_clock_set_rtcsec(sec);
}

static struct tm _datetime_local() {
	struct tm timeinfo;
	time_t now = time(NULL);
	localtime_r(&now, &timeinfo);
	return timeinfo;
}

char* unios_rtc_local_string() {
	static char str[64];
	struct tm timeinfo = _datetime_local();
	strftime(str, sizeof(str), "%c", &timeinfo);
	return str;
}

std_err_t unios_rtc_set(int year, int month, int day, int hour, int minute, int second) {
	struct tm dt = {0};
	dt.tm_year = year - 1900;
	dt.tm_mon = month - 1;
	dt.tm_mday = day;
	dt.tm_hour = hour;
	dt.tm_min = minute;
	dt.tm_sec = second;
	time_t rtcsec = mktime(&dt);
	return unios_rtcsec_set(rtcsec);
}

std_err_t unios_rtc_get(int *year, int *month, int *day, int *hour, int *minute, int *second, int *weekday) {
	struct tm dt = _datetime_local();
	if(year) *year = dt.tm_year + 1900;
	if(month) *month = dt.tm_mon + 1;
	if(day) *day = dt.tm_mday;
	if(hour) *hour = dt.tm_hour;
	if(minute) *minute = dt.tm_min;
	if(second) *second = dt.tm_sec;
	if(weekday) *weekday = dt.tm_wday;
	return STD_ERR_OK;
}

std_err_t unios_rtc_timezone_set(const char *tz) {
	return STD_ERR_NOT_SUPPORTED;
}


void unios_disable_interrupts() {
	taskDISABLE_INTERRUPTS();
}

void unios_enable_interrupts() {
	taskENABLE_INTERRUPTS();
}

/// @brief 当前是否在中断中
//#define osIsInIsr() 			xPortInIsrContext()
//#define osIsInIsr() 			xPortIsInsideInterrupt()

bool unios_is_in_isr() {
	#if USE_ZYNQ_A53
		extern uint64_t ullPortInterruptNesting; // 表示中断嵌套层数 in port.c
		return	(ullPortInterruptNesting != 0);
	#elif USE_ZYNQ_R5 || USE_ZYNQ_A9
		extern uint32_t ulPortInterruptNesting;  // 表示中断嵌套层数 in port.c
		return (ulPortInterruptNesting != 0);
	#elif USE_MICROBLAZE
		extern volatile uint32_t ulTaskSwitchRequested;
		return (ulTaskSwitchRequested != 1);
	#else
		#error("No unios_is_in_isr() defined !")
	#endif
}

// ======================================================================================
// 关于线程
// ======================================================================================

std_err_t unios_thread_create(unios_thread_func_t func, void *cookie, unios_thread_priority_t priority, size_t stack_size, uint64_t cpu_affinity, unios_thread_t* pt) {
    if(!func || priority >= UNIOS_THREAD_PRIORITY_MAX) return STD_ERR_INVALID_ARG;

    size_t ncpu = 0;
    if(cpu_affinity) {
        // 获取 CPU 内核数量
        ncpu = unios_get_cpu_core_count();
        if(!ncpu) return STD_ERR_FAIL;
        if(cpu_affinity >= (uint64_t)(1ULL << ncpu)) return STD_ERR_OUT_OF_RANGE;
    }

    TaskHandle_t taskHandle;
	BaseType_t bt = xTaskCreate((TaskFunction_t)func, NULL, stack_size, (void *const)cookie, priority, &taskHandle);
	if(bt != pdPASS) return STD_ERR_FAIL;
	if(pt) *pt = (unios_thread_t)taskHandle;

    return STD_ERR_OK;
}

void unios_thread_close(unios_thread_t thread) {
	if(unios_is_in_isr()) {
		// 在中断处理程序中不允许删除线程！
		// 删除任务是一个复杂的操作，可能触发调度（如果删除的是当前任务），而中断上下文中不允许触发上下文切换！
	} else {
		vTaskDelete((TaskHandle_t)thread);
	}
}

unios_thread_t unios_thread_this() {
	// do nothing
	return (unios_thread_t)-1;
}


// ======================================================================================
// 关于临界区
// ======================================================================================

std_err_t unios_critical_section_init(unios_critical_section_t* pcs) {
    if(!pcs) return STD_ERR_INVALID_ARG;

    *pcs = (unios_critical_section_t)xSemaphoreCreateBinary();
    if (*pcs == NULL) return STD_ERR_NO_MEM;

    return STD_ERR_OK;
}

std_err_t unios_critical_section_enter(unios_critical_section_t cs, long wait_timeout_ms) {
    if(!cs) return STD_ERR_INVALID_ARG;

    if(unios_is_in_isr()) return STD_ERR_INVALID_STATE; // 不允许在中断中使用 unios_critical_section !
    BaseType_t ret = xSemaphoreTake((SemaphoreHandle_t)cs, (TickType_t)(wait_timeout_ms / portTICK_PERIOD_MS));
    if(ret != pdTRUE) return STD_ERR_TIMEOUT;

    return STD_ERR_OK;
}

void unios_critical_section_leave(unios_critical_section_t cs) {
    if(!cs) return;
    unios_is_in_isr() ? xSemaphoreGiveFromISR((SemaphoreHandle_t)cs, NULL) : xSemaphoreGive((SemaphoreHandle_t)cs);
}

void unios_critical_section_destroy(unios_critical_section_t *cs/*in,out*/) {
    if(!cs || !(*cs)) return;
    
    // 释放临界区
    unios_critical_section_leave((*cs));

    vSemaphoreDelete((SemaphoreHandle_t)(*cs));

    *cs = (unios_critical_section_t)NULL;
}


// ======================================================================================
// 关于锁
// ======================================================================================

std_err_t unios_lock_init(unios_lock_t* plock, size_t count) {
    if(!plock || count < 1) return STD_ERR_INVALID_ARG;

	// do nothing
    *plock = (unios_lock_t)-1;

    return STD_ERR_OK;
}

std_err_t unios_lock(unios_lock_t lock, long wait_timeout_ms) {
    if(!lock) return STD_ERR_INVALID_ARG;

    return STD_ERR_NOT_SUPPORTED;
}

std_err_t unios_unlock(unios_lock_t lock) {
    if(!lock) return STD_ERR_INVALID_ARG;
    return STD_ERR_NOT_SUPPORTED;
}

void unios_lock_destroy(unios_lock_t *lock) {
    if(!lock || !(*lock)) return;
    
    // 释放锁
    unios_unlock(*lock);

    *lock = (unios_lock_t)NULL;
}


// ======================================================================================
// 关于事件
// ======================================================================================

std_err_t unios_event_init(unios_event_t* pevent, bool manual_reset, bool init_state) {
    if(!pevent) return STD_ERR_INVALID_ARG;

    *pevent = (unios_event_t)-1;
    return STD_ERR_NOT_SUPPORTED;
}

std_err_t unios_event_set(unios_event_t event, bool signal) {
    if(!event) return STD_ERR_INVALID_ARG;

	return STD_ERR_NOT_SUPPORTED;
}

std_err_t unios_event_wait(unios_event_t event, long wait_timeout_ms) {
    if(!event) return STD_ERR_INVALID_ARG;

    return STD_ERR_NOT_SUPPORTED;
}

void unios_event_destroy(unios_event_t *pevent /*in,out*/) {
    if(!pevent || !(*pevent)) return;

    // do nothing
    *pevent = (unios_event_t)-1;
}
